﻿using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Web.Script.Serialization;
using HtmlAgilityPack;
using System.Collections.Concurrent;
using System.IO;
using System.Xml.Serialization;
using System.ComponentModel;
using MahApps.Metro;
using System.Diagnostics;
using System.Windows.Controls;
using System.Windows.Forms;


namespace intelliSys.NankaiUtilities.EventSynchronizer
{
    public class IntegerValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            int result = -1;
            bool success = int.TryParse(value.ToString(), out result);
            if (result <= 0) success = false;
            ValidationResult validationResult = new ValidationResult(success, "提醒时间应当为正整数");
            return validationResult;
        }
    }
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MetroWindow
    {

        enum SessionPhase
        {
            None,
            LoggingIn,
            AcquiringConsent,
            Redirecting,
        }

        enum CalendarImportGuideStatus
        {
            ControlPanel,
            AcquiringData,
            SelectingCalendar,
            SelectingSource,
            SelectingData,
            SyncingCalendar
        }

        SessionPhase sessionPhase = SessionPhase.None;
        CalendarImportGuideStatus guideStatus = CalendarImportGuideStatus.ControlPanel;
        Storyboard transistIn;
        Storyboard transistOut;
        Storyboard superBusy;
        Storyboard expand;
        Storyboard shrink;
        public MainWindow()
        {
            InitializeComponent();
            transistIn = this.Resources["TransistIn"] as Storyboard;
            transistOut = this.Resources["TransistAway"] as Storyboard;
            superBusy = this.Resources["SuperBusy"] as Storyboard;
            expand = (this.Resources["ExpandHeight"] as Storyboard);
            shrink = (this.Resources["Shrink"] as Storyboard);

            this.browser.LoadCompleted += browser_LoadCompleted;
            this.browser.Navigating += browser_Navigating;
            this.Closed += MainWindow_Closed;
            // guideStatus = CalendarImportGuideStatus.SelectingCalendar;
            // browser.Visibility = System.Windows.Visibility.Collapsed;

            //CalendarPickGrid.Visibility = System.Windows.Visibility.Visible;
            //CollectionViewSource.GetDefaultView(calendarList.ItemsSource).GroupDescriptions.Clear();
            //ICollectionView viewCollection = CollectionViewSource.GetDefaultView(calendarList.ItemsSource);
            //viewCollection.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
            InitAsync();
            remindTime.DataContext = syncOptions;
            remindTime.Text = "15";
            ChangeTheme(Setting.Default.Accent);
        }

        NotifyIcon trayIcon;
        private void AddTrayIcon()
        {
            if (trayIcon != null)
            {
                return;
            }
            trayIcon = new NotifyIcon
            {
                Icon = new System.Drawing.Icon("nku.ico"),
                Text = "NKU Event Live Sync Background Agent"
            };
            trayIcon.Visible = true;
            trayIcon.MouseDoubleClick += turnOn_Click;
            trayIcon.BalloonTipClicked += turnOn_Click;

            System.Windows.Forms.ContextMenu menu = new System.Windows.Forms.ContextMenu();

            System.Windows.Forms.MenuItem closeItem = new System.Windows.Forms.MenuItem();
            closeItem.Text = "关闭";
            closeItem.Click += new EventHandler(delegate { this.Close(); });

            System.Windows.Forms.MenuItem turnOn = new System.Windows.Forms.MenuItem();
            turnOn.Text = "恢复";
            turnOn.Click += turnOn_Click;

            menu.MenuItems.Add(turnOn);
            menu.MenuItems.Add(closeItem);

            trayIcon.ContextMenu = menu;    //设置NotifyIcon的右键弹出菜单
        }


        private void RemoveTrayIcon()
        {
            if (trayIcon != null)
            {
                trayIcon.Dispose();
            }
        }

        void MainWindow_Closed(object sender, EventArgs e)
        {
            try
            {
                Stream stream = File.Open(Helpers.SynchronizedEventFilePath, FileMode.Open);
                XmlSerializer xmlS = new XmlSerializer(typeof(List<string>));
                xmlS.Serialize(stream, syncOptions.AlreadySynchronized);
                Setting.Default.Accent = accentRotator % 5;
                RemoveTrayIcon();
            }
            catch
            {
            }
        }

        private void InitAsync()
        {
            browser.Navigate(Helpers.GetSignInUri());
        }

        void browser_Navigating(object sender, NavigatingCancelEventArgs e)
        {
            browser.Visibility = System.Windows.Visibility.Collapsed;
            (this.Resources["SuperBusy"] as Storyboard).Begin();
            if (e.Uri.ToString() == Helpers.GetSignInUri())
            {
                transitioning1.Content = "准备登录...";
                sessionPhase = SessionPhase.LoggingIn;
            }
            if (e.Uri.ToString().Contains("ppsecure"))
            {
                transitioning1.Content = "获取您的授权...";
                sessionPhase = SessionPhase.AcquiringConsent;
            }
            if (e.Uri.ToString().StartsWith("http://www.liangluo.net"))
            {
                sessionPhase = SessionPhase.Redirecting;
            }
        }

        void browser_LoadCompleted(object sender, NavigationEventArgs e)
        {
            browser.Visibility = System.Windows.Visibility.Visible;
            (this.Resources["SuperBusy"] as Storyboard).Stop();
            if (sessionPhase == SessionPhase.LoggingIn)
            {
                (this.Resources["ExpandHeight"] as Storyboard).Begin();
            }
            if (sessionPhase == SessionPhase.AcquiringConsent)
            {
            }
            if (sessionPhase == SessionPhase.Redirecting)
            {
                if (e.Uri.AbsoluteUri.Contains("code="))
                {
                    string auth_code = Regex.Split(e.Uri.AbsoluteUri, "code=")[1];
                    Helpers.AuthCode = auth_code;
                    (this.Resources["Shrink"] as Storyboard).Begin();
                    transitioning1.Content = "收集信息...";
                    superBusy.Begin();
                    browser.Visibility = System.Windows.Visibility.Collapsed;
                    WebClient accessTokenAccessClient = new WebClient();
                    accessTokenAccessClient.DownloadStringCompleted += accessToken_DownloadStringCompleted;
                    accessTokenAccessClient.DownloadStringAsync(new Uri(Helpers.GetAccessTokenRequestURI()));

                }
            }

        }

        private void DrawUI_ControlPanel()
        {
            ControlPanelGrid.Visibility = System.Windows.Visibility.Visible;
            transistIn.Begin(ControlPanelGrid);
        }

        private void DrawUI_CalendarPick()
        {
            transistOut.Begin(ControlPanelGrid);
            banner.Text = "选择日历...";
            ControlPanelGrid.Visibility = System.Windows.Visibility.Collapsed;
            CalendarPickGrid.Visibility = System.Windows.Visibility.Visible;
            transistIn.Begin(CalendarPickGrid);
        }

        private void DrawUI_EventPick()
        {
            transistOut.Begin(CalendarPickGrid);
            banner.Text = "选择日历...";
            EventSourcePickGrid.Visibility = System.Windows.Visibility.Collapsed;
            EventPickGrid.Visibility = System.Windows.Visibility.Visible;
            transistIn.Begin(EventPickGrid);
        }

        private void next_Click_1(object sender, RoutedEventArgs e)
        {
            if (guideStatus == CalendarImportGuideStatus.ControlPanel)
            {
                guideStatus = CalendarImportGuideStatus.SelectingCalendar;
                next.IsEnabled = false;
                DrawUI_CalendarPick();
                IssueCalendarRequest();
            }
            else if (guideStatus == CalendarImportGuideStatus.SelectingCalendar)
            {
                next.IsEnabled = false;
                guideStatus = CalendarImportGuideStatus.SelectingSource;
                DrawUI_EventSourcePick();
            }
            else if (guideStatus == CalendarImportGuideStatus.SelectingSource)
            {
                next.IsEnabled = false;
                guideStatus = CalendarImportGuideStatus.AcquiringData;
                DrawUI_EventPick();
                IssueEventRequest();
            }
            else if (guideStatus == CalendarImportGuideStatus.AcquiringData)
            {
                syncOptions.SelectedEvents = eventList.SelectedItems.Cast<LiveEvent>();
                next.IsEnabled = false;
                guideStatus = CalendarImportGuideStatus.SyncingCalendar;
                DrawUI_SyncCalendar();
                IssueCalendarSync();
            }
            else if (guideStatus == CalendarImportGuideStatus.SyncingCalendar)
            {
                this.Close();
            }
        }

        private void DrawUI_EventSourcePick()
        {
            eventSourceList.ItemsSource = this.eventSources;
            banner.Text = "数据源...";
            CalendarPickGrid.Visibility = System.Windows.Visibility.Collapsed;
            transistIn.Begin(EventSourcePickGrid);
            EventSourcePickGrid.Visibility = System.Windows.Visibility.Visible;
            next.IsEnabled = false;
        }

        private void DrawUI_Done()
        {
            banner.Text = "完成...";
            EventPickGrid.Visibility = System.Windows.Visibility.Collapsed;
            transistIn.Begin(DoneGrid);
            DoneGrid.Visibility = System.Windows.Visibility.Visible;
            next.Content = "关闭";
        }

        private void IssueCalendarSync()
        {
            ThreadPool.QueueUserWorkItem(o =>
                {
                    object Lock = new object();
                    int currentIdx = 0;
                    StringBuilder sb = new StringBuilder();
                    Parallel.ForEach<LiveEvent>(syncOptions.SelectedEvents, new Action<LiveEvent>(lectureEvent =>
                    {
                        try
                        {
                            lock (Lock)
                            {
                                currentIdx++;
                                this.Dispatcher.Invoke(new Action(() =>
                                    {
                                        transitioningPerecentage.Content = (int)(100 * (double)currentIdx / (double)syncOptions.SelectedEvents.Count()) + "%";
                                        transitioning1.Content = lectureEvent.Title;
                                        sb.Append(lectureEvent.Title);
                                        sb.Append("\r\n");
                                    }));
                            }
                            var answer = Helpers.LiveEventToJSON(lectureEvent, syncOptions);
                            WebClient webC = new WebClient();
                            webC.Headers.Set("Content-Type", "application/json");
                            webC.Headers.Add("Authorization", "Bearer " + Helpers.AccessToken);
                            webC.Encoding = Encoding.UTF8;
                            var results = webC.UploadData(Helpers.ApiUri + "me/events", "POST", Encoding.UTF8.GetBytes(answer.ToArray()));
                            syncOptions.AlreadySynchronized.Add(lectureEvent.Title.Trim());
                        }
                        catch
                        {
                        }
                    }));
                    this.Dispatcher.Invoke(new Action(() =>
                        {
                            superBusy.Stop();
                            DrawUI_Done();
                            succeededEvents.Text = sb.ToString();
                            next.IsEnabled = true;
                        }));
                });

        }

        private void DrawUI_SyncCalendar()
        {
            superBusy.Begin();
            shrink.Begin();
            transitioning1.Content = "正在准备同步...";
        }

        private void IssueEventRequest()
        {
            transitioningPerecentage.Visibility = System.Windows.Visibility.Visible;
            eventProgress.Visibility = System.Windows.Visibility.Visible;
            eventLonelyGrid.Visibility = System.Windows.Visibility.Collapsed;
            eventList.Visibility = System.Windows.Visibility.Collapsed;
            //WebClient eventClientHtmlRequester = new WebClient();
            //eventClientHtmlRequester.DownloadStringCompleted += eventClientHtmlRequester_DownloadStringCompleted;
            //eventClientHtmlRequester.Encoding = Encoding.GetEncoding("GB2312");
            //eventClientHtmlRequester.DownloadStringAsync(new Uri("http://chem.nankai.edu.cn/ShowMore.php?class=51"));
            var sources = eventSourceList.SelectedItems;
            ThreadPool.QueueUserWorkItem(o =>
                   {
                       results.Clear();
                       foreach (var eventSource in sources)
                       {
                           results.AddRange((eventSource as ILiveEventSource).GenerateEventList());
                       }
                       this.Dispatcher.Invoke(new Action(() =>
                       {
                           eventList.ItemsSource = results;
                           RefreshEventStatus();
                           eventList.Visibility = System.Windows.Visibility.Visible;
                           eventProgress.Visibility = System.Windows.Visibility.Collapsed;
                           eventShowWhenDone.Visibility = System.Windows.Visibility.Visible;
                           expand.Begin();
                       }));
                   });

        }

        List<LiveEvent> results = new List<LiveEvent>();

        private void IssueCalendarRequest()
        {
            calendarProgress.Visibility = System.Windows.Visibility.Visible;
            calendarLonelyGrid.Visibility = System.Windows.Visibility.Collapsed;
            WebClient calendarClient = new WebClient();
            calendarClient.DownloadStringCompleted += calendarClient_DownloadStringCompleted;
            calendarClient.Encoding = Encoding.UTF8;
            calendarClient.DownloadStringAsync(MakeApiRequest("me/calendars"));
        }

        Dictionary<string, object[]> calendarData;
        LiveCalendar[] liveCalendar;
        void calendarClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            calendarData = deserializeJsonNestedDict(e.Result);
            var calendars = calendarData["data"];
            liveCalendar = new LiveCalendar[calendars.Length];
            for (int i = 0; i < liveCalendar.Count(); i++)
            {
                liveCalendar[i] = new LiveCalendar();
                var name = (calendars[i] as Dictionary<string, object>)["name"].ToString();
                var desc = (calendars[i] as Dictionary<string, object>)["description"].ToString();
                var id = (calendars[i] as Dictionary<string, object>)["id"].ToString();
                liveCalendar[i].ID = id;
                liveCalendar[i].Description = desc == "" ? "没有描述" : desc;
                liveCalendar[i].Name = name;
            }
            this.Dispatcher.Invoke(new Action(() =>
                {
                    calendarProgress.Visibility = System.Windows.Visibility.Collapsed;
                    if (liveCalendar.Length == 0)
                    {
                        calendarLonelyGrid.Visibility = System.Windows.Visibility.Visible;
                    }
                    else
                    {
                        calendarLonelyGrid.Visibility = System.Windows.Visibility.Collapsed;
                    }
                    calendarList.ItemsSource = liveCalendar;
                }));

        }

        private Dictionary<string, object[]> deserializeJsonNestedDict(string json)
        {
            var jss = new JavaScriptSerializer();
            var d = jss.Deserialize<Dictionary<string, object[]>>(json);
            return d;
        }

        private Dictionary<string, string> deserializeJson(string json)
        {
            var jss = new JavaScriptSerializer();
            var d = jss.Deserialize<Dictionary<string, string>>(json);
            return d;
        }

        void accessToken_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(o =>
                {
                    tokenData = deserializeJson(e.Result);
                    if (tokenData.ContainsKey("access_token"))
                    {
                        Helpers.AccessToken = tokenData["access_token"];
                        WebClient meRequest = new WebClient();
                        meRequest.DownloadStringCompleted += meRequest_DownloadStringCompleted;
                        meRequest.DownloadStringAsync(MakeApiRequest("me"));
                    }
                });
        }

        private static Uri MakeApiRequest(string request)
        {
            return new Uri(Helpers.ApiUri + request + "?access_token=" + Helpers.AccessToken);
        }

        void meRequest_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(o =>
                {
                    tokenData = deserializeJson(e.Result);
                    this.Dispatcher.Invoke(new Action(() =>
                                      {
                                          userName.Text = tokenData["name"];
                                          userImage.Source = new BitmapImage(new Uri(Helpers.ApiUri + "me/picture?access_token=" + Helpers.AccessToken, UriKind.RelativeOrAbsolute));
                                          superBusy.Stop();
                                          superBusyRing.IsActive = false;
                                          DrawUI_ControlPanel();
                                      }));
                });
        }


        public Dictionary<string, string> tokenData { get; set; }
        public SyncOptions syncOptions = new SyncOptions();
        public IEnumerable<ILiveEventSource> eventSources;
        private void RefreshCalendar(object sender, RoutedEventArgs e)
        {
            IssueCalendarRequest();
        }

        private void calendarList_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
        {
            System.Windows.Controls.ListBox lb = sender as System.Windows.Controls.ListBox;
            next.IsEnabled = lb.SelectedItems.Count > 0;
            if (lb == calendarList)
            {
                if (liveCalendar != null && liveCalendar.Length != 0)
                {
                    syncOptions.SelectedLiveCalendar = liveCalendar[calendarList.SelectedIndex];
                }
            }
        }

        private void remindTime_TextChanged_1(object sender, TextChangedEventArgs e)
        {
            int result;
            int.TryParse(remindTime.Text, out result);
            next.IsEnabled = result > 0;
        }

        private void RefreshEvent(object sender, RoutedEventArgs e)
        {
            IssueEventRequest();
        }

        private void Hyperlink_Click_1(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start((sender as Hyperlink).NavigateUri.ToString());
        }

        private void exceptionFilter_Click_1(object sender, RoutedEventArgs e)
        {
            RefreshEventStatus();
        }

        private void dateFilter_Click_1(object sender, RoutedEventArgs e)
        {
            RefreshEventStatus();
        }

        private IEnumerable<LiveEvent> DateFilteredPipe(IEnumerable<LiveEvent> events)
        {
            return events.Where<LiveEvent>(o =>
                {
                    return o.StartTime > DateTime.Now || o.StartTime == default(DateTime);
                });
        }

        private IEnumerable<LiveEvent> ExceptionFilteredPipe(IEnumerable<LiveEvent> events)
        {
            return events.Where<LiveEvent>(o => o.AttentionRequested == false);
        }

        private IEnumerable<LiveEvent> SynchronizedFilerPipe(IEnumerable<LiveEvent> events)
        {
            return events.Where<LiveEvent>(o => syncOptions.AlreadySynchronized.Contains(o.Title) == false);
        }

        void DrawUI_BusyFilteringEvents()
        {
            next.IsEnabled = false;
            eventProgress.Visibility = System.Windows.Visibility.Visible;
            eventList.IsEnabled = false;
        }

        void DrawUI_EventsFiltered()
        {
            eventProgress.Visibility = System.Windows.Visibility.Collapsed;
            eventList.IsEnabled = true;
        }

        private void RefreshEventStatus()
        {
            IEnumerable<LiveEvent> itemssource = results.OrderBy<LiveEvent, DateTime>(new Func<LiveEvent, DateTime>(le => le.StartTime));
            //viewCollection.Filter = null;
            bool syncedFiltered = false, dateFiltered = false, exceptionFiltered = false;
            if (syncedFilter.IsChecked.Value)
            {
                itemssource = SynchronizedFilerPipe(itemssource);
            }
            if (dateFilter.IsChecked.Value)
            {
                itemssource = DateFilteredPipe(itemssource);
            }
            ShowExceptionEventGridIfNecessary(itemssource);
            if (exceptionFilter.IsChecked.Value)
            {
                itemssource = ExceptionFilteredPipe(itemssource);
            }
            if (itemssource.Count() == 0)
            {
                eventLonelyGrid.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                eventLonelyGrid.Visibility = System.Windows.Visibility.Collapsed;
            }
            //itemssource.Count();
            eventList.ItemsSource = itemssource;
            // CollectionViewSource.GetDefaultView(eventList.ItemsSource).GroupDescriptions.Clear();
            //viewCollection.Filter

        }
        ListCollectionView viewCollection;
        PropertyGroupDescription description = new PropertyGroupDescription("EventSource", new EventGroupConverter());
        private void ShowExceptionEventGridIfNecessary(IEnumerable<LiveEvent> liveEvents)
        {
            int cnt = liveEvents.Where<LiveEvent>(x =>
                {
                    return !x.AttentionRequested;
                }).Count();
            if (liveEvents.Count() > cnt)
            {
                eventShowOnException.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                eventShowOnException.Visibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void refreshEventStatus_Click_1(object sender, RoutedEventArgs e)
        {
            RefreshEventStatus();
        }

        private void syncedFilter_Click_1(object sender, RoutedEventArgs e)
        {
            RefreshEventStatus();
        }
        int accentRotator = Setting.Default.Accent;
        private void userInfoGrid_MouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
        {
            ChangeTheme(++accentRotator % 5);
        }

        private void ChangeTheme(int accent)
        {
            MahApps.Metro.ThemeManager.ChangeTheme(this, MahApps.Metro.ThemeManager.DefaultAccents.ToArray()[accent % 5], Theme.Light);
        }


        Thread probingThread;
        AutoResetEvent autoResetEvent = new AutoResetEvent(false);
        private void turnOn_Click(object sender, EventArgs e)
        {
            this.Visibility = System.Windows.Visibility.Visible;
        }

        private void backgroundServiceSwitch_Click_1(object sender, RoutedEventArgs e)
        {
            AddTrayIcon();
            trayIcon.ShowBalloonTip(5000, "在后台运行", "当前程序正在后台运行。", ToolTipIcon.Info);
            this.Visibility = System.Windows.Visibility.Collapsed;
            autoResetEvent.Set();
            if (probingThread == null)
            {
                probingThread = new Thread(o =>
                    {
                        while (true)
                        {
                            Thread.Sleep(3600000);
                            try
                            {
                                if (EventProbing.NKUEventProber.DetectedEvents())
                                {
                                    trayIcon.ShowBalloonTip(5000, "检查到新的事件", "单击以查看", ToolTipIcon.Info);
                                    autoResetEvent.WaitOne();
                                }
                            }
                            catch
                            {
                            }
                        }
                    });
                probingThread.IsBackground = true;
                probingThread.Start();
            }

            //try
            //{
            //    if (backgroundServiceSwitch.IsChecked.Value)
            //    {
            //        ServiceTools.ServiceInstaller.InstallAndStart("NKUEventProbingService", "NKU Event Live Sync Probing Service", Directory.GetCurrentDirectory() + "\\NKUEventProbingService.exe");
            //    }
            //    else
            //    {
            //        ServiceTools.ServiceInstaller.Uninstall("NKUEventProbingService");
            //        Process process = new Process();
            //        ProcessStartInfo p = new ProcessStartInfo();
            //        process.StartInfo = p;
            //        p.Verb = "runas";
            //        p.FileName = "NKU Event Live Sync.exe";
            //        this.Close();
            //        process.Start();
            //    }
            //}
            //catch
            //{
            //    Process process = new Process();
            //    ProcessStartInfo p = new ProcessStartInfo();
            //    process.StartInfo = p;
            //    p.Verb = "runas";
            //    p.FileName = "NKU Event Live Sync.exe";
            //    this.Close();
            //    process.Start();
            //}
        }
    }
    class EventGroupConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (value as ILiveEventSource).Name;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
